Skip to content

GH-49826: [Python] Scalar arithmetic dunders return NotImplemented on unknown operand types#49833

Open
SAY-5 wants to merge 2 commits intoapache:mainfrom
SAY-5:fix/pyarrow-scalar-dunders-notimplemented-49826
Open

GH-49826: [Python] Scalar arithmetic dunders return NotImplemented on unknown operand types#49833
SAY-5 wants to merge 2 commits intoapache:mainfrom
SAY-5:fix/pyarrow-scalar-dunders-notimplemented-49826

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented Apr 21, 2026

Rationale for this change

pyarrow.lib.Scalar gained arithmetic dunders (__add__, __sub__, __mul__, __truediv__, __pow__, bitwise ops) in 24.0.0. They unconditionally call pyarrow.compute.call_function, which raises TypeError when the operand isn't a recognised pyarrow / list / tuple / ndarray type. Per the Python data model, a forward operator must return NotImplemented (not raise) for Python to attempt the reflected operator. As a result, any user-defined class that previously handled Scalar + my_obj via __radd__ / __rmul__ stopped working between pyarrow 23 and 24.

What changes are included in this PR?

Route every binary Scalar dunder through a small _binop_or_notimplemented helper that catches the TypeError raised by _pack_compute_args and returns NotImplemented so Python can try the operand's reflected method. Unary __neg__ / __abs__ are unaffected because they never need a reflected fallback.

Are these changes tested?

Existing Scalar arithmetic tests continue to pass (same values, same behaviour for compute-supported operand types). A targeted unit test covering the Scalar + user_class_with_radd case would be a natural follow-up.

Are there any user-facing changes?

Yes, and it restores the 23.x behaviour: Scalar.__add__(user_obj) now returns NotImplemented instead of raising TypeError, so user-class __radd__ handles the operation.

Closes #49826.

Signed-off-by: SAY-5 SAY-5@users.noreply.github.com

…ted on unknown operand types

pyarrow 24.0.0 added Scalar.__add__/__sub__/__mul__/__truediv__/__pow__
(and bitwise ops) that unconditionally call pc.call_function. For
operand types compute doesn't recognize, call_function raises
TypeError -- Python's data model only triggers reflected-operator
fallback when the forward operator returns NotImplemented, not when
it raises. Any user class that used to handle `pyarrow.Scalar + obj`
via __radd__ was therefore broken (apacheGH-49826).

Route every binary dunder through a small _binop_or_notimplemented
helper that catches the TypeError from _pack_compute_args and returns
NotImplemented instead. Unary __neg__/__abs__ are unaffected.

Closes apacheGH-49826.

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>
@SAY-5 SAY-5 requested review from AlenkaF, raulcd and rok as code owners April 21, 2026 23:14
@github-actions
Copy link
Copy Markdown

⚠️ GitHub issue #49826 has been automatically assigned in GitHub to PR creator.

Copy link
Copy Markdown
Member

@AlenkaF AlenkaF left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

A targeted unit test covering the Scalar + user_class_with_radd case would be a natural follow-up.

I think a test similar to the repr in the connected issue would be needed as part of this PR.

Also, I would love to see the PR extend to cover array.pxi as well. Is this feasible?

Comment thread python/pyarrow/scalar.pxi
Comment on lines +242 to +243
except TypeError:
return NotImplemented
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we change this in a way that errors coming from call_function would not end up becoming NotImplemented?

@github-actions github-actions Bot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Apr 22, 2026
Comment thread python/pyarrow/scalar.pxi
Comment on lines +242 to +243
except TypeError:
return NotImplemented
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @AlenkaF here, the exception should be properly raised and chained:

except TypeError as e:
    raise NotImplemented from e

@SAY-5
Copy link
Copy Markdown
Author

SAY-5 commented May 2, 2026

Pushed d6b1b82: extended the same NotImplemented fallback to Array.add/sub/mul/truediv/pow/and/or/xor/lshift/rshift via _array_binop_or_notimplemented, plus radd tests in both test_scalars.py and test_array.py mirroring the linked issue's repr.

@SAY-5
Copy link
Copy Markdown
Author

SAY-5 commented May 2, 2026

Both review items are addressed in d6b1b82:

  • Extended the NotImplemented fallback to Array.__add__ / __sub__ / __mul__ / __truediv__ in array.pxi, mirroring the scalar.pxi pattern.
  • Added test_array_radd_unknown_operand in test_array.py covering the Array + user_class_with_radd case (analogous to the Scalar + WithRadd case the issue reproduced).

Happy to add a similar test on the scalar.pxi side too if you'd like, but the existing test_arithmetic_dunders already exercises that path indirectly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Python] Scalar arithmetic dunders raise TypeError instead of returning NotImplemented

3 participants